package cmd

import (
	"fmt"
	_func "gin/func"
	ftpWoker "gin/server/ftp"
	"runtime/debug"
	"strconv"
	"time"
)

type Ftp struct {
	Log _func.StyleLog
}

type MasterWorkerInfo struct {
	FtpId       int64 //用户FTPid
	UserId      int64
	FtpType     string // ftp类型
	FtpUserName string // 账号
	FtpPassword string // 密码
	FtpAddress  string // 地址
	Port        string // 端口
	UserStatus  int64  //用户状态
	MasterClose int64
	SendChan    chan string `json:"-"` //发送数据
	ReceiveChan chan string `json:"-"` //接收数据
	wokerStatus bool
	num         int
	Frist       bool
}

//var i int

// var WorkerArr = make(map[int64]ftpWoker.Worker)
var MasterInfo []MasterWorkerInfo
var WokerArr []ftpWoker.Woker
var linshiWokerArr []ftpWoker.Woker

func (f *Ftp) Run() {

	fmt.Println("执行代码")
	f.Log.NewLog("0")
	defer func() {
		if r := recover(); r != nil {
			// 处理panic，记录日志或返回错误信息给客户端

			f.Log.FtpLogGer3("主进程捕获错误", r)
			f.Log.FtpLogGer3("主进程捕获错误", debug.Stack())
			fmt.Println("协程错误:", debug.Stack())
			fmt.Println("协程错误:", r)
		}
	}()

	ftpS := ftpWoker.NewFtpS()
	fmt.Println("开始启动")
	isExists := true
	runNum := 0

	var tmp []MasterWorkerInfo
	for {

		//没有就加入

		//判断变动  变动前判断是否存在 修改状态

		//woker 信息处理
		ftpinfo := ftpS.GetFtpInfo()
		//fmt.Println(ftpinfo)
		for _, ftp := range ftpinfo {
			isExists = true
			for keyNum, master := range MasterInfo {
				key := keyNum
				if master.FtpId == ftp.Id && MasterInfo[key].UserStatus != ftp.UserConnectStatus {
					//存在就更新数据
					MasterInfo[key].UserId = ftp.UserId
					MasterInfo[key].UserStatus = ftp.UserConnectStatus
					MasterInfo[key].FtpType = ftp.FtpType
					MasterInfo[key].FtpUserName = ftp.FtpUserName
					MasterInfo[key].FtpPassword = ftp.FtpPassword
					MasterInfo[key].FtpAddress = ftp.FtpAddress
					MasterInfo[key].Port = ftp.Port
					runNum = 0 //有信息变动也打印一次
				}

				if master.FtpId == ftp.Id {
					isExists = false
					continue
				}
			}
			//不存在就添加数据
			if isExists && ftp.UserConnectStatus == 1 {
				MasterInfo = append(MasterInfo, MasterWorkerInfo{
					UserId:      ftp.UserId,
					FtpId:       ftp.Id,
					UserStatus:  ftp.UserConnectStatus,
					FtpType:     ftp.FtpType,
					FtpUserName: ftp.FtpUserName,
					FtpPassword: ftp.FtpPassword,
					FtpAddress:  ftp.FtpAddress,
					Port:        ftp.Port,
					SendChan:    make(chan string, 3600),
					ReceiveChan: make(chan string, 3600), // 为接收通道设置缓冲区
					wokerStatus: false,
					Frist:       true,
					MasterClose: 0, //主协程 关闭状态  默认不关闭
				})
			}
		}
		//启动用户连接了  没有启动的woker 的woker
		for key, master := range MasterInfo {
			if master.wokerStatus == false && master.UserStatus == 1 {
				idx := key //协程
				go f.MasterWoker(&MasterInfo[idx])
				MasterInfo[idx].wokerStatus = true
				f.Log.FtpLogGer2("启动了新的woker", MasterInfo[idx])
			}
		}

		//监听woker是否正常
		for key, _ := range MasterInfo {
			idx := key //协程
			select {
			case response := <-MasterInfo[idx].ReceiveChan:
				switch response {
				case "XT":
					//收到心跳  重置 0
					//fmt.Println("收到心跳", MasterInfo[idx].FtpId)
					MasterInfo[idx].num = 0
					break
				default:
					break
				}
			default:
				break
			}
		}

		deleteWorker := false //woker变动控制

		for keyNum, _ := range MasterInfo {
			key := keyNum
			//用户主动停止
			if MasterInfo[key].UserStatus == 0 && MasterInfo[key].wokerStatus == true {
				MasterInfo[key].SendChan <- "UserStop"
				MasterInfo[key].wokerStatus = false
				now := time.Now()
				unixTime := now.Unix()
				MasterInfo[key].MasterClose = unixTime
				f.Log.FtpLogGer2("用户主动停止", MasterInfo[key].FtpId)
				deleteWorker = true
			} else if MasterInfo[key].num >= 10 {
				//心跳中断
				MasterInfo[key].SendChan <- "XtStop"
				MasterInfo[key].wokerStatus = false
				now := time.Now()
				unixTime := now.Unix()
				MasterInfo[key].MasterClose = unixTime
				f.Log.FtpLogGer2("心跳中断", MasterInfo[key].FtpId)
				deleteWorker = true
			} else {
				f.Log.FtpLogGer2("发送心跳", MasterInfo[key].FtpId)
				MasterInfo[key].SendChan <- "XT"
			}
		}

		//执行 心跳 + 1
		for keyNum, _ := range MasterInfo {
			key := keyNum
			MasterInfo[key].num = MasterInfo[key].num + 1
			if MasterInfo[key].num > 11 {
				var log _func.StyleLog
				log.NewLog("try")
				log.FtpLogGer3("心跳异常:", MasterInfo[key])

			}
		}

		//采用条件转移法  安全删除 结构体   把关掉的woker 全部删除掉
		if deleteWorker {
			var newMasterInfo []MasterWorkerInfo
			for _, worker := range MasterInfo {
				if worker.wokerStatus == true {
					newMasterInfo = append(newMasterInfo, worker)
				} else {
					tmp = append(tmp, worker)
					f.Log.FtpLogGer2("清理连接", worker)
				}
			}
			MasterInfo = newMasterInfo
		}

		for keyNum, _ := range tmp {
			key := keyNum
			now := time.Now()
			unixTime := now.Unix()
			timeNum := unixTime - tmp[keyNum].MasterClose
			//超过3小时 清理
			if timeNum > 10800 {
				if tmp[key].ReceiveChan != nil {
					close(tmp[key].ReceiveChan)
				}
				if tmp[key].SendChan != nil {
					close(tmp[key].SendChan)
				}
				tmp = append(tmp[:keyNum], tmp[keyNum+1:]...)
			}
		}

		if runNum != len(MasterInfo) {
			runNum = len(MasterInfo)
			f.Log.FtpLogGer3("线程信息", MasterInfo)
			f.Log.FtpLogGer3("待清理的线程信息", tmp)
		} else {
			f.Log.FtpLogGer3("线程信息数量", runNum)
			//fmt.Println("线程信息数量:", runNum)
		}
		time.Sleep(3 * time.Second)
	}
}

func (f *Ftp) MasterWoker(workerInfo *MasterWorkerInfo) {

	fmt.Println("MasterWoker 启动")
	var log _func.StyleLog
	//now := time.Now()
	//unixTime := now.Unix()
	//str := strconv.FormatInt(unixTime, 10)
	strId := strconv.FormatInt(workerInfo.FtpId, 10)
	log.NewLog("master_" + strId)
	//fmt.Println("日志id", strId)

	defer func() {
		if r := recover(); r != nil {
			// 处理panic，记录日志或返回错误信息给客户端
			log.FtpLogGer3("MasterWoker进程捕获错误", r)
			log.FtpLogGer3("MasterWoker进程捕获错误", debug.Stack())
			fmt.Println("MasterWoker协程错误:", debug.Stack())
			fmt.Println("MasterWoker协程错误:", r)
		}
	}()

	ftpS := ftpWoker.NewFtpS()
	wokerFtp := ftpWoker.Woker{
		UserId:             workerInfo.UserId,
		FtpId:              workerInfo.FtpId,
		UserStatus:         1,
		FtpType:            workerInfo.FtpType,
		FtpUserName:        workerInfo.FtpUserName,
		FtpPassword:        workerInfo.FtpPassword,
		FtpAddress:         workerInfo.FtpAddress,
		Port:               workerInfo.Port,
		SendChan:           make(chan string, 3660),
		ReceiveChan:        make(chan string, 3660), // 为接收通道设置缓冲区
		HeartbeatId:        "master: id：" + strId + " ",
		FTPWokerStatus:     false,            //默认没有启动
		Frist:              workerInfo.Frist, //workerInfo.Frist, //测试环境 可以设置为 false   测试连接过程
		FristConnectStatus: false,
	}

	//master 超时次数
	MasterNum := 0
	//master 状态
	MasterStatus := true
	//ftp状态
	eventStatus := 0
	//ftp信息备注
	eventDesc := ""
	//重启ftp次数
	reFtpNum := 0

	for {

		xtStatus := false
		FristStatus := false
		wokerStatus := false
		//根据状态判断是否启动woker

		if wokerFtp.FTPWokerStatus == false {
			cache := wokerFtp            //储存旧的缓存通道防止 子协程卡死 无法回收
			cache.FTPWokerStatus = false //储存旧的缓存通道防止 子协程卡死 无法回收
			wokerFtp = ftpWoker.Woker{
				UserId:             workerInfo.UserId,
				FtpId:              workerInfo.FtpId,
				UserStatus:         1,
				FtpType:            workerInfo.FtpType,
				FtpUserName:        workerInfo.FtpUserName,
				FtpPassword:        workerInfo.FtpPassword,
				FtpAddress:         workerInfo.FtpAddress,
				Port:               workerInfo.Port,
				SendChan:           make(chan string, 3660),
				ReceiveChan:        make(chan string, 3660), // 为接收通道设置缓冲区
				HeartbeatId:        "master: id：" + strId + " ",
				FTPWokerStatus:     false,            //默认没有启动
				Frist:              workerInfo.Frist, //workerInfo.Frist, //测试环境 可以设置为 false   测试连接过程
				FristConnectStatus: false,
			}

		}

		if wokerFtp.FTPWokerStatus == false && wokerFtp.UserStatus == 1 {
			fmt.Println("打开新woker")
			switch wokerFtp.FtpType {
			case "GG":
				ggS := ftpWoker.NewGgFtp()
				go ggS.GgWorker(&wokerFtp)
				log.FtpLogGer3("打开新woker", wokerFtp)
				break
			case "PP":

				ggS := ftpWoker.NewGgFtp()

				go ggS.GgWorker(&wokerFtp)
				log.FtpLogGer3("打开新woker", wokerFtp)
				break
			case "GP":
				//创建协程通信通道
				gpS := ftpWoker.NewGpFtp()
				go gpS.GgWorker(&wokerFtp)
				log.FtpLogGer3("打开新woker", wokerFtp)
				break
			case "NO":
				break
			}
			wokerFtp.FTPWokerStatus = true
		}

		//fmt.Println("连接状态", wokerFtp.FTPWokerStatus)
		//发送心跳给主进程
		workerInfo.ReceiveChan <- "XT"

		//接收主进程 信号
		select {
		case response := <-workerInfo.SendChan:
			switch response {
			case "XT":
				//fmt.Println("接收到主进程心跳", workerInfo.FtpId)
				MasterNum = 0
				break
			case "UserStop":
				//主进程发信号停止
				log.FtpLogGer("用户发起主动停止：UserStop")
				MasterStatus = false
			case "XtStop":
				//主进程发心跳停止   逻辑上不可能发送
				log.FtpLogGer("主进程发心跳停止：XtStop")
				MasterStatus = false
				break
			default:
				break
			}
		default:
			break
		}
		//fmt.Println("master线程计数器", MasterNum)
		//心跳计数超时停止
		MasterNum = MasterNum + 1
		if MasterNum > 10 {
			log.FtpLogGer3("主线程心跳超时：", MasterNum)
			MasterStatus = false
		}

		//消息接收
		msg := true
		eventStatus = 0
		for msg {
			//接收消息
			select {
			case response := <-wokerFtp.ReceiveChan:
				log.FtpLogGer3("消息：", response)
				switch response {
				//退出连接消息
				case "endUserStop":
					eventStatus = 1
					eventDesc = "用户主动关闭-接收到关闭信号-删除woker数据"
					log.FtpLogGer("收到关闭消息")
					log.FtpLogGer3("用户主动关闭-接收到关闭信号-删除woker数据", wokerFtp)
					break
				//woker创建成功消息
				case "WokerCreatSuccess":
					wokerStatus = true

					break
				case "UserErr":
					eventStatus = 1
					eventDesc = "检测到用户连接异常"
					break
				//异常退出消息
				case "tryCloser":
					if wokerFtp.Frist {
						//首次连接也有异常的情况 无法 直接发送失败状态
						eventStatus = 1
						eventDesc = "首次连接失败,直接关闭 原因：连接异常"
					} else {
						eventStatus = 2
						eventDesc = "重启"
						log.FtpLogGer("协程崩溃了")
						fmt.Println("协程崩溃,执行重启")
						//异常关闭
					}
					break
				//心跳消息
				case "xintiao":
					log.FtpLogGer("接收到心跳")
					wokerFtp.WokerOutTime = 0
					xtStatus = true
					break
				//数据更新消息
				case "dataUpdate":
					log.FtpLogGer("数据更新")
					break
				//第一次连接失败消息
				case "FirstConnectFailed":

					if wokerFtp.Frist {
						eventStatus = 1
						eventDesc = "首次连接失败,直接关闭 原因：连接失败"
						log.FtpLogGer("首次连接失败,直接关闭 原因：连接失败")
					} else {
						eventStatus = 2
						eventDesc = "重启连接失败,再次连接"
						log.FtpLogGer("重启连接失败,再次连接")
					}

					break
				//第一次连接成功消息
				case "FirstConnectSuccess":
					FristStatus = true
					if wokerFtp.Frist {
						//如果是第一次连接成功就把第一次设置为 false  代表连接成功过了
						wokerFtp.Frist = false
						workerInfo.Frist = false
					}
					reFtpNum = 0
					wokerFtp.FristConnectStatus = true

					log.FtpLogGer("连接成功")
					break
				//每次连接成功消息
				case "ConnectSuccess":
					log.FtpLogGer("每次连接成功")
					break
				case "dataOutStop":
					eventStatus = 1
					eventDesc = "数据超时未更新关闭"

					break
				case "xtOutStop":
					eventDesc = "子协已退出"
					break
				}
				break
			default:
				//没有数据了退出循环
				msg = false
				break
			}
		}

		if xtStatus {
			xtStatus = false
			//心跳
			go ftpS.FtpInfoM.UpdateEventStatus(wokerFtp.FtpId, 1)
			time.Sleep(1 * time.Second)
		}

		if FristStatus {
			FristStatus = false
			go ftpS.FtpInfoM.UpdateFtpInfo(wokerFtp.FtpId, 1, "连接成功")
			time.Sleep(1 * time.Second)
		}
		if wokerStatus {
			wokerStatus = false
			//woker 创建成功
			go ftpS.FtpInfoM.SetWokerStatus(wokerFtp.FtpId, 1)
			time.Sleep(1 * time.Second)
		}

		//发送消息
		if eventStatus != 1 {

			//用户主动关闭
			if MasterStatus == false {
				wokerFtp.SendChan <- "UserStop"
				eventStatus = 1
				eventDesc = "用户主动关闭"
				log.FtpLogGer3("用户主动关闭- 发送关闭命令", wokerFtp.FtpId)
			}

			//首次连接超时关闭
			if wokerFtp.WokerOutTime > (60) && wokerFtp.Frist == true {
				//心跳超时后 关闭 次级协程 后续关闭会报错
				wokerFtp.SendChan <- "xtOutStop"
				eventStatus = 1
				eventDesc = "首次连接超时,直接关闭"
				log.FtpLogGer3("首次连接超时,直接关闭", wokerFtp)
			}

			//心跳超时检测 3600
			if wokerFtp.WokerOutTime > (3600) && eventStatus == 0 {
				wokerFtp.SendChan <- "xtOutStop"
				eventStatus = 1
				eventDesc = "心跳超时关闭"
				log.FtpLogGer3("心跳超时发起停止", wokerFtp)
			}

			//超时停止检测后强行停止 一般都是协程崩溃了 消息发不出来 接收不到 3660
			if wokerFtp.WokerOutTime > 3660 && eventStatus == 0 {
				wokerFtp.SendChan <- "xtOutStop"
				eventStatus = 1
				eventDesc = "心跳超时强行关闭"
				log.FtpLogGer3("已发送心跳停止,协程卡死强制停止", wokerFtp)
			}

			//心跳超时重启  10分钟 没反应重启
			if wokerFtp.WokerOutTime > 600 && eventStatus == 0 {
				wokerFtp.SendChan <- "xtOutStop"
				eventStatus = 2
				eventDesc = "执行中卡死超10分钟,重新连接"
				log.FtpLogGer3("执行中卡死超10分钟,重新连接", wokerFtp)
			}

			//重试连接检测
			if reFtpNum > 10 {
				eventStatus = 1
				eventDesc = "重试连接超过10次,主动关闭连接"
				log.FtpLogGer3("重试连接超过10次,主动关闭连接", wokerFtp)
			}

			if eventStatus == 0 {
				log.FtpLogGer3("发送心跳：", wokerFtp.HeartbeatId)
				wokerFtp.SendChan <- "XT"
			}
		}

		switch eventStatus {
		case 1:
			//fmt.Println("关闭")
			//关闭连接
			ftpS.FtpInfoM.CloseFtpConnect(wokerFtp.FtpId, eventDesc)

			wokerFtp.FristConnectStatus = false
			return
		case 2:
			//fmt.Println("执行重启")
			//重启woker
			ftpS.FtpInfoM.ReStartFtpConnect(wokerFtp.FtpId, eventDesc)
			reFtpNum = reFtpNum + 1
			wokerFtp.FristConnectStatus = false
			wokerFtp.FTPWokerStatus = false
			eventStatus = 0
			//重置超时时间
			break
		case 3:

		default:
			eventStatus = 0
			//fmt.Println("状态为：0")
			//不操作
		}
		wokerFtp.WokerOutTime = wokerFtp.WokerOutTime + 1
		fmt.Println("心跳超时", wokerFtp.WokerOutTime)
		str := strconv.FormatInt(wokerFtp.WokerOutTime, 10)
		log.FtpLogGer(wokerFtp.HeartbeatId + "心跳超时:" + str)
		time.Sleep(1 * time.Second)
	}
}

//启动ftp

//关闭ftp

// 删除指定 ID 的结构体
func removePersonByID(people []ftpWoker.Woker, id int64) []ftpWoker.Woker {
	// 创建一个新的切片
	result := []ftpWoker.Woker{}

	// 遍历原数组
	for _, person := range people {
		// 如果当前结构体的 ID 不等于目标 ID，则将其添加到新切片中
		if person.FtpId != id {
			result = append(result, person)
		}
	}
	return result
}
